package com.example.shuiyin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.shuiyin.dto.ProcessRecordDto;
import com.example.shuiyin.entity.ProcessRecord;
import com.example.shuiyin.entity.User;
import com.example.shuiyin.enums.MediaType;
import com.example.shuiyin.enums.ProcessStatus;
import com.example.shuiyin.enums.SourceType;
import com.example.shuiyin.exception.AppException;
import com.example.shuiyin.mapper.ProcessRecordMapper;
import com.example.shuiyin.parsers.MediaParser;
import com.example.shuiyin.parsers.ParserFactory;
import com.example.shuiyin.processors.MediaProcessor;
import com.example.shuiyin.processors.ProcessorFactory;
import com.example.shuiyin.service.MediaParserService;
import com.example.shuiyin.service.MediaProcessorService;
import com.example.shuiyin.service.MediaService;
import com.example.shuiyin.service.ProcessRecordService;
import com.example.shuiyin.service.StorageService;
import com.example.shuiyin.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class MediaServiceImpl implements MediaService {

    private final ProcessRecordService processRecordService;
    private final MediaParserService mediaParserService;
    private final MediaProcessorService mediaProcessorService;
    private final StorageService storageService;

    @Override
    public ProcessRecord parseMediaUrl(String url, Long userId) {
        // 1. 创建处理记录
        ProcessRecord record = ProcessRecord.builder()
                .userId(userId)
                .sourceType(SourceType.LINK)
                .sourceUrl(url)
                .status(ProcessStatus.WAITING)
                .createdAt(LocalDateTime.now())
                .build();
        
        record = processRecordService.createRecord(record);
        
        // 2. 异步解析和处理
        processMediaAsync(record);
        
        return record;
    }

    @Override
    public ProcessRecord processUploadedFile(MultipartFile file, Long userId) throws IOException {
        // 生成唯一文件名
        String originalFilename = file.getOriginalFilename();
        String uniqueFilename = UUID.randomUUID() + "_" + originalFilename;
        
        // 存储文件
        String filePath = storageService.store(file, uniqueFilename);
        
        // 确定媒体类型
        MediaType mediaType = determineMediaType(file);
        
        // 创建处理记录
        ProcessRecord record = ProcessRecord.builder()
                .userId(userId)
                .sourceType(SourceType.UPLOAD)
                .originalFilename(originalFilename)
                .mediaType(mediaType)
                .sourceUrl(filePath)
                .status(ProcessStatus.WAITING)
                .createdAt(LocalDateTime.now())
                .build();
        
        record = processRecordService.createRecord(record);
        
        // 异步处理
        processMediaAsync(record);
        
        return record;
    }

    @Override
    public List<ProcessRecord> processUploadedFiles(List<MultipartFile> files, Long userId) throws IOException {
        List<ProcessRecord> records = new ArrayList<>();
        
        for (MultipartFile file : files) {
            ProcessRecord record = processUploadedFile(file, userId);
            records.add(record);
        }
        
        return records;
    }
    
    @Async("taskExecutor")
    public void processMediaAsync(ProcessRecord record) {
        try {
            // 更新状态为处理中
            record.setStatus(ProcessStatus.PROCESSING);
            processRecordService.updateRecord(record);
            
            String sourceFilePath = record.getSourceUrl();
            
            if (record.getSourceType() == SourceType.LINK) {
                // 解析媒体链接
                try {
                    // 解析媒体类型
                    MediaType mediaType = mediaParserService.detectMediaType(record.getSourceUrl());
                    record.setMediaType(mediaType);
                    
                    // 解析下载链接
                    String downloadUrl = mediaParserService.parseUrl(record.getSourceUrl());
                    
                    // 下载媒体文件
                    sourceFilePath = mediaParserService.downloadMedia(downloadUrl);
                    record.setSourceUrl(sourceFilePath);
                    
                    // 更新记录
                    processRecordService.updateRecord(record);
                } catch (Exception e) {
                    log.error("解析媒体链接失败: {}", e.getMessage(), e);
                    updateRecordToFailed(record, "解析媒体链接失败: " + e.getMessage());
                    return;
                }
            }
            
            // 处理媒体文件
            try {
                String resultPath = mediaProcessorService.process(sourceFilePath, record.getMediaType());
                
                // 存储结果文件
                String resultUrl = storageService.saveResult(resultPath, record.getId());
                
                // 更新记录状态
                record.setResultUrl(resultUrl);
                record.setStatus(ProcessStatus.COMPLETED);
                record.setProcessedAt(LocalDateTime.now());
                processRecordService.updateRecord(record);
                
                // 清理临时文件
                storageService.deleteTempFile(sourceFilePath);
                storageService.deleteTempFile(resultPath);
            } catch (Exception e) {
                log.error("处理媒体文件失败: {}", e.getMessage(), e);
                updateRecordToFailed(record, "处理媒体文件失败: " + e.getMessage());
            }
        } catch (Exception e) {
            log.error("媒体处理异常: {}", e.getMessage(), e);
            updateRecordToFailed(record, "媒体处理异常: " + e.getMessage());
        }
    }
    
    private void updateRecordToFailed(ProcessRecord record, String errorMessage) {
        record.setStatus(ProcessStatus.FAILED);
        record.setErrorMessage(errorMessage);
        processRecordService.updateRecord(record);
    }
    
    private MediaType determineMediaType(MultipartFile file) {
        String contentType = file.getContentType();
        String filename = file.getOriginalFilename();
        
        if (contentType != null) {
            if (contentType.startsWith("video/")) {
                return MediaType.VIDEO;
            } else if (contentType.startsWith("image/")) {
                return MediaType.IMAGE;
            }
        }
        
        // 根据文件扩展名判断
        if (filename != null) {
            String extension = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
            if (extension.equals("mp4") || extension.equals("avi") || extension.equals("mov")) {
                return MediaType.VIDEO;
            } else if (extension.equals("jpg") || extension.equals("jpeg") || extension.equals("png")) {
                return MediaType.IMAGE;
            }
        }
        
        return MediaType.TEXT;
    }
}